import { Client, Message, StompSubscription } from '@stomp/stompjs'
import { useState, useRef, useCallback, useEffect } from 'react'
import Taro from '@tarojs/taro'
import { UserPanel } from '@/types/global'

// ========================
// 🔧 工具函数：创建适配 Taro 的 WebSocket 代理（用于 /ws-native）
// ========================
function createTaroWebSocket(url: string) {
  let socketOpen = false
  let socketTask: Taro.SocketTask | null = null
  const messageQueue: string[] = []

  const ws: any = {
    send: (data: string) => {
      if (socketOpen && socketTask) {
        try {
          socketTask.send({ data })
        } catch (err) {
          console.error('WebSocket 发送失败:', err)
        }
      } else {
        messageQueue.push(data)
      }
    },
    close: () => {
      socketTask?.close({})
    },
    onopen: null,
    onmessage: null,
    onerror: null,
    onclose: null
  }

  Taro.connectSocket({
    url,
    success: () => console.log('[WebSocket] 连接请求已发送'),
    fail: (err) => {
      console.error('[WebSocket] 连接失败:', err)
      ws.onerror && ws.onerror(err)
    }
  }).then((task) => {
    socketTask = task

    socketTask.onOpen(() => {
      socketOpen = true
      console.log('[WebSocket] 已打开')
      ws.onopen && ws.onopen()
      messageQueue.forEach(msg => ws.send(msg))
      messageQueue.length = 0
    })

    socketTask.onMessage((res) => {
      const data = typeof res.data === 'string' ? res.data : ''
      ws.onmessage && ws.onmessage({ data })
    })

    socketTask.onError((err) => {
      console.error('[WebSocket] 错误:', err)
      ws.onerror && ws.onerror(err)
    })

    socketTask.onClose(() => {
      console.log('[WebSocket] 已关闭')
      ws.onclose && ws.onclose()
    })
  })

  return ws
}

// ========================
// 🧩 全局 WebSocket 状态管理
// ========================
interface RoomResource {
  status: string
  playerIps: string[]
  playerPanels: Record<string, UserPanel>
  blackBag: any[]
  cardListA: any[]
  cardListB: any[]
  cardListC: any[]
  cardListD: any[]
  gemPositon: string[]
  gemSource: any[]
  currentPlayerIp: string
  nextPlayerIp: string
  isFilled: boolean
  round: number
  keepCards: Record<string, any[]>
  buyCards: Record<string, any[]>
  gameConfig: any
  publicPrivilege: number
  canUsePrivilege: boolean
  canRefillGemBoard: boolean
  canPerformMainAction: boolean
}

interface GlobalWebSocketState {
  stompClient: Client | null
  subscription: StompSubscription | null
  isConnected: boolean
  connectionStatus: string
  roomResource: RoomResource | null
  userIp: string
}

// 创建全局状态
const globalState: GlobalWebSocketState = {
  stompClient: null,
  subscription: null,
  isConnected: false,
  connectionStatus: '未连接',
  roomResource: null,
  userIp: ''
}

// 回调函数集合
const callbacks: {
  onRoomResourceUpdate: ((resource: RoomResource) => void)[]
  onRoomCommand: ((command: any) => void)[]
  onConnectionStatusChange: ((status: string) => void)[]
} = {
  onRoomResourceUpdate: [],
  onRoomCommand: [],
  onConnectionStatusChange: []
}

// ========================
// 🔄 全局 WebSocket Hook
// ========================
export const useGlobalWebSocket = () => {
  const [connectionStatus, setConnectionStatus] = useState<string>(globalState.connectionStatus)
  const [roomResource, setRoomResource] = useState<RoomResource | null>(globalState.roomResource)
  const [isConnected, setIsConnected] = useState<boolean>(globalState.isConnected)
  const [userIp, setUserIp] = useState<string>(globalState.userIp)

  // 注册回调函数
  const registerCallback = useCallback((
    type: 'onRoomResourceUpdate' | 'onRoomCommand' | 'onConnectionStatusChange',
    callback: Function
  ) => {
    callbacks[type].push(callback as any)
    
    // 返回取消注册函数
    return () => {
      const index = callbacks[type].indexOf(callback as any)
      if (index > -1) {
        callbacks[type].splice(index, 1)
      }
    }
  }, [])

  // 发送指令到服务器
  const sendCommand = useCallback((destination: string, body: any): void => {
    if (!globalState.stompClient || !globalState.isConnected) {
      console.error('STOMP客户端未连接')
      return
    }

    globalState.stompClient.publish({
      destination,
      body: JSON.stringify(body),
      headers: { 'content-type': 'application/json' }
    })
  }, [])

  // 连接 WebSocket
  const connectWebSocket = useCallback((roomId: string) => {
    if (!roomId) {
      Taro.showToast({ title: '请先创建房间', icon: 'none' })
      return Promise.resolve({ success: false, error: '请先创建房间' })
    }

    if (globalState.isConnected) {
      Taro.showToast({ title: '已连接', icon: 'none' })
      return Promise.resolve({ success: false, error: '已连接' })
    }

    return new Promise<{ success: boolean; error?: string }>((resolve) => {
      const client = new Client({
        brokerURL: 'wss://www.gemduel.xin/ws-native',
        webSocketFactory: () => createTaroWebSocket('wss://www.gemduel.xin/ws-native'),
        connectHeaders: {},
        onConnect: () => {
          console.log('✅ STOMP 连接成功')
          globalState.connectionStatus = '已连接'
          globalState.isConnected = true
          globalState.stompClient = client

          // 通知所有监听者连接状态变化
          callbacks.onConnectionStatusChange.forEach(callback => callback('已连接'))

          // 订阅房间资源更新
          globalState.subscription = client.subscribe(`/topic/room/${roomId}`, (message: Message) => {
            try {
              const data = JSON.parse(message.body)
              if (data.type === 'room_resource_update') {
                globalState.roomResource = data.payload
                // 通知所有监听者房间资源更新
                callbacks.onRoomResourceUpdate.forEach(callback => callback(data.payload))
                console.log('📦 房间资源更新:', data.payload)
              }
              if (data.type === 'room_command') {
                // 通知所有监听者房间指令
                callbacks.onRoomCommand.forEach(callback => callback(data.payload))
                console.log('📦 房间指令:', data.payload)
              }
            } catch (e) {
              console.error('解析消息失败:', e)
            }
          })

          resolve({ success: true })
        },
        onStompError: (frame) => {
          console.error('❌ STOMP 错误:', frame)
          globalState.connectionStatus = '连接失败'
          callbacks.onConnectionStatusChange.forEach(callback => callback('连接失败'))
          Taro.showToast({ title: '连接失败', icon: 'none' })
          resolve({ success: false, error: '连接失败' })
        },
        onDisconnect: () => {
          console.log('🔌 STOMP 已断开')
          globalState.connectionStatus = '已断开'
          globalState.isConnected = false
          callbacks.onConnectionStatusChange.forEach(callback => callback('已断开'))
        },
        reconnectDelay: 5000,
        heartbeatIncoming: 4000,
        heartbeatOutgoing: 4000
      })

      client.activate()
      globalState.stompClient = client
    })
  }, [])

  // 断开连接
  const disconnectWebSocket = useCallback(() => {
    if (globalState.stompClient && globalState.isConnected) {
      globalState.stompClient.deactivate()
    }
    if (globalState.subscription) {
      globalState.subscription.unsubscribe()
      globalState.subscription = null
    }
    globalState.isConnected = false
    globalState.connectionStatus = '已断开'
    callbacks.onConnectionStatusChange.forEach(callback => callback('已断开'))
  }, [])

  // 加入房间
  const joinRoom = useCallback((roomId: string) => {
    if (!globalState.stompClient || !globalState.isConnected || !roomId) {
      return Promise.resolve({ success: false, error: '未连接或房间ID无效' })
    }

    sendCommand('/app/join_room', { roomId })
    
    console.log('📤 加入房间:', roomId)
    return Promise.resolve({ success: true })
  }, [sendCommand])

  // 添加玩家到房间
  const addPlayerToRoom = useCallback(async (roomId: string) => {
    if (!roomId) {
      Taro.showToast({ title: '请填写ID', icon: 'none' })
      return { success: false, error: '请填写ID' }
    }
    
    try {
      const res = await Taro.request({
        url: `https://www.gemduel.xin/room/addPlayer/${roomId}`,
        method: 'POST',
        header: { 'Content-Type': 'application/json' }
      })
      
      if (res.data.success) {
        Taro.showToast({ title: '添加成功' })
        globalState.userIp = res.data.userIp
        setUserIp(res.data.userIp)
        return { success: true, userIp: res.data.userIp }
      } else {
        return { success: false, error: '添加失败' }
      }
    } catch (error) {
      console.error('添加失败:', error)
      Taro.showToast({ title: '请求失败', icon: 'none' })
      return { success: false, error: '请求失败' }
    }
  }, [])

  // 获取房间资源（HTTP）
  const getRoomResource = useCallback(async (roomId: string) => {
    if (!roomId) {
      return { success: false, error: '房间ID无效' }
    }
    
    try {
      const res = await Taro.request({
        url: `https://www.gemduel.xin/room/resource/${roomId}`,
        method: 'GET',
        header: { 'Content-Type': 'application/json' }
      })
      
      if (res.data.success) {
        globalState.roomResource = res.data.data
        setRoomResource(res.data.data)
        Taro.showToast({ title: '获取成功' })
        return { success: true, data: res.data.data }
      } else {
        return { success: false, error: '获取失败' }
      }
    } catch (error) {
      console.error('获取资源失败:', error)
      Taro.showToast({ title: '请求失败', icon: 'none' })
      return { success: false, error: '请求失败' }
    }
  }, [])

  // 发送游戏指令
  const sendGameCommand = useCallback((command: string, payload: any = {}, targetRoomId?: string) => {
    if (!command) {
      Taro.showToast({ title: '请输入指令', icon: 'none' })
      return
    }

    if (!globalState.stompClient || !globalState.isConnected) {
      Taro.showToast({ title: '未连接', icon: 'none' })
      return
    }

    const body = {
      roomId: targetRoomId,
      command,
      payload
    }
    
    sendCommand('/app/game_command', body)
    Taro.showToast({ title: '指令已发送' })
  }, [sendCommand])

  // 具体游戏指令方法
  const playerReady = useCallback((playerIp: string, roomId?: string): void => {
    sendGameCommand('player_ready', { playerIp }, roomId)
  }, [sendGameCommand])

  // 清理函数
  const cleanup = useCallback(() => {
    // 注意：全局 WebSocket 不应该在组件卸载时断开连接
    // 只有在应用完全退出时才应该断开连接
    console.log('全局 WebSocket 清理（但不实际断开连接）')
  }, [])

  // 同步全局状态到本地状态
  useEffect(() => {
    const unsubscribeConnectionStatus = registerCallback('onConnectionStatusChange', (status: string) => {
      setConnectionStatus(status)
      setIsConnected(status === '已连接')
    })

    const unsubscribeRoomResource = registerCallback('onRoomResourceUpdate', (resource: RoomResource) => {
      setRoomResource(resource)
    })

    // 初始化状态
    setConnectionStatus(globalState.connectionStatus)
    setIsConnected(globalState.isConnected)
    setRoomResource(globalState.roomResource)
    setUserIp(globalState.userIp)

    return () => {
      unsubscribeConnectionStatus()
      unsubscribeRoomResource()
    }
  }, [registerCallback])

  return {
    // 状态
    connectionStatus,
    roomResource,
    isConnected,
    userIp,
    
    // 基础方法
    connectWebSocket,
    joinRoom,
    sendGameCommand,
    disconnectWebSocket,
    getRoomResource,
    addPlayerToRoom,
    cleanup,
    
    // 具体游戏指令方法
    playerReady,
    
    // 全局 WebSocket 管理方法
    registerCallback,
    sendCommand,
    
    // 全局状态
    globalState: globalState
  }
}